package edu.uj.petri.model;

import edu.uj.petri.commands.Memento;

/**
 * @author Piotrek
 */
public class NormalArc extends Arc {
    private NormalArcImpl impl;
    
    /** Event code for Observed */
    public final static int WEIGHT_CHANGE = 8845;
    
    /**
     * creates a normal arc.
     * @throws IllegalArgumentException when given nodes are incorrect
     */
    NormalArc(Node from, Node to, NormalArcImpl impl) {
        super(from, to, impl.getArcImpl());
        this.impl = impl;
        impl.setWeight(1);
        
        if (from instanceof Place && to instanceof Transition) {
            ((Transition)to).addIncomingArc(this);
        } else if (from instanceof Transition && to instanceof Place) {
            ((Transition)from).addOutgoingArc(this);
        } else {
            throw new IllegalArgumentException("normal arc connects place " +
                    "with transition");
        }
    }
    
    public int getWeight() {
        return impl.getWeight();
    }
    
    /**
     * sets arc weight
     * @throws IllegalArgumentException when given weight less than 1
     */
    public void setWeight(int weight) {
        if (weight < 1)
            throw new IllegalArgumentException("weight has to be at least 1");
        impl.setWeight(weight);
        observerList.notifyAllSubscribers(WEIGHT_CHANGE);
    }
    
    /**
     * moves tokens from connected places.
     */
    public void fire() {
        if (getFrom() instanceof Place) {
            Place from = (Place)getFrom();
            from.deleteTokens(impl.getWeight());
        } else {
            Place to = (Place)getTo();
            to.addTokens(impl.getWeight());
        }
    }
    
    public boolean canBeFired() {
        if (getFrom() instanceof Place) {
            Place from = (Place)getFrom();
            return from.getTokens() >= impl.getWeight();
        } else { // arc leads from transition to place
            return true;
        }
    }
    
    public Memento getMemento() {
        ArcMemento retval = new ArcMemento();
        retval.implMemento = impl.getMemento();
        retval.arcMemento = super.getMemento();
        return retval;
    }
    
    public void applyMemento(Memento memento) {
        if (!(memento instanceof ArcMemento))
            throw new IllegalArgumentException("invalid memento");
        
        ArcMemento am = (ArcMemento)memento;
        impl.applyMemento(am.implMemento);
        super.applyMemento(am.arcMemento);
        observerList.notifyAllSubscribers(WEIGHT_CHANGE);
    }
    
    private static final long serialVersionUID = -3940922709458845136L;
    
    static class ArcMemento extends Memento {
        private Memento implMemento;
        private Memento arcMemento;
    }
}
